// SPDX-License-Identifier: GPL-2.0

#include "phy-nx-usb.h"
#include "phy-nx-usb-reg.h"
#include "phy-nx-usb-common.h"

static int usbphy_suspend(void __iomem *reg_base)
{
	int ret = 0;

	ret = lb_nx_usbphy_suspend(reg_base);

	return ret;
}

static int usbphy_resume(void __iomem *reg_base)
{
	int ret = 0;

	ret = lb_nx_usbphy_resume(reg_base);

	return ret;
}

static int n7v7_usbphy_suspend(struct lb_nx_usbphy *nx_usbphy, int is_suspend)
{
	if (is_suspend)
		return usbphy_suspend(nx_usbphy->reg_base);	/* suspend */
	else
		return usbphy_resume(nx_usbphy->reg_base);	/* resume */
}

static int usbphy_init(void __iomem *reg_base)
{
	int			ret;
	char			efuse_value;
	void __iomem		*reg_addr;
	reg_usb_usbctrl_t	usb_ctrl_reg;
	reg_usb_phycfg_t	usb_phycfg;

	/*
	 * note:
	 * For the following operations, please see USB_Program_Guide
	 */

	/*
	 * 1. config USBCTRL
	 */
	reg_addr = reg_base + USBCTRL;
	usb_ctrl_reg.val = READREG32(reg_addr);

	/* 1.1 bit[31:28] bug fixed */
	usb_ctrl_reg.bits.rsvd4 = 0;
	usb_ctrl_reg.bits.sim_spdup = 0;
	usb_ctrl_reg.bits.susp_sof_fixed = 1;

	/* 1.2 n7v7 must be enabled the "dma check ahb write end" */
	usb_ctrl_reg.bits.dma_check_hwend = 1;

	WRITEREG32(reg_addr, usb_ctrl_reg.val);

	udelay(10);

	/*
	 * 2. config PHYTUNE
	 */
	/* nothing need to do! */

	/*
	 * 3. config PHYCFG
	 */
	reg_addr = reg_base + PHYCFG;
	usb_phycfg.val = READREG32(reg_addr);

	/* 3.1 phy res */
#define USB20_OTG_EFUSE_ID		0x11
	usb_phycfg.bits.resusb20_en = 1;

	ret = lb_nx_usbphy_read_efuse_ref(USB20_OTG_EFUSE_ID,
					  &efuse_value);
	if (!ret)
		usb_phycfg.bits.resusb20_sel = efuse_value & 0x7F;

	/* 3.2 phy ldo */
	usb_phycfg.bits.ldo3318_lpn_ctrl = 0;

	WRITEREG32(reg_addr, usb_phycfg.val);

	return 0;
}

static int n7v7_usbphy_init(struct lb_nx_usbphy *nx_usbphy)
{
	return usbphy_init(nx_usbphy->reg_base);
}

struct lb_nx_usbphy_soc_ops n7v7_usbphy_ops = {
	.init		= n7v7_usbphy_init,
	.suspend	= n7v7_usbphy_suspend,
};

struct lb_nx_usbphy_soc_ops *lb_usbphy_get_n7v7_ops(void)
{
	return &n7v7_usbphy_ops;
}
